package io.yx.flx.aspect;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.FileUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import io.yx.flx.entity.FileInfo;
import io.yx.flx.util.SHAUtil;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.File;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.Optional;


/**
 * 代理oss上传方法，上传之前查询数据库是否存在此文件的信息
 * 如果存在则直接返回数据库存储的信息，否则调用目标方法执行上传并记录信息
 */
public class UploadProxy implements MethodInterceptor {

    private static final Log log = LogFactory.get();

    /**
     * 代理实现逻辑
     *
     * @param obj    cglib生产的代理对象
     * @param method 原对象的方法
     * @param args   原方法的参数
     * @param proxy  代理方法
     * @return 方法执行结果
     * @throws Throwable 目标方法可能抛出的异常
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if (Objects.equals(method.getName(), "ossUpload") && args[0] instanceof File) {
            File file = (File) args[0];
            String sha_key = SHAUtil.messageDigestFile(file, SHAUtil.SHA);
            //获得文件大小
            long size = file.length();

            try {
                List<Entity> entities = Db.use().find(Entity.create("file_info").set("size", size).set("sha_key", sha_key));
                Optional<Entity> any = entities.stream().findAny();
                if (any.isPresent()) {
                    // 已上传过此文件
                    FileInfo fileInfo = any.get().toBean(FileInfo.class);
                    // 更新引用次数
                    Db.use().execute("update file_info set reference=reference + 1, update_time = ? where sha_key = ? and size = ?", DateUtil.now(), fileInfo.getShaKey(), fileInfo.getSize());
                    return fileInfo;
                }
            } catch (Exception ignore) {
            }

            // 读取文件SHA1值并查询数据库是否存在此匹配的数据，如果有则直接返回原url
            // 如果不存在则执行目标方法的invoke，并将返回的url写入到数据库
            TimeInterval timeInterval = DateUtil.timer();
            Object invokeResult = proxy.invokeSuper(obj, args);
            log.info("oss上传耗时:{}ms，文件大小：{}", timeInterval.interval(), FileUtil.readableFileSize(file));
            log.info("toJsonString:{}", JSONUtil.toJsonStr(invokeResult));

            // 写入数据库
            if (invokeResult instanceof FileInfo) {
                FileInfo resultFileInfo = (FileInfo) invokeResult;
                resultFileInfo.setShaKey(sha_key);
                resultFileInfo.setSize(size);
                resultFileInfo.setReference(1);
                int insert = Db.use().insert(Entity.parse(resultFileInfo, true, true));
                log.info("新增文件记录：{}", insert);
            }

            return invokeResult;
        } else {
            return proxy.invokeSuper(obj, args);
        }
    }
}
